Rem
bbdoc: Provides streaming for the OpenAL audio driver. 
End Rem
Type TOpenALAudioStream Extends TAudioStream 

	Field _buffercount:Int = 16
	Field _buffers:Int[_buffercount]
	Global _buffersize:Int = 1024*8
	Field _bufferbanks:TBank[_buffercount]
	Field _source:Int

	Method Delete()
		If _source Stop
	EndMethod

	Function Build:TOpenALAudioStream(Music:TMusic,Paused:Int)
		Local This:TOpenALAudioStream = New TOpenALAudioStream
		This.Music = Music
		This.Music.PlayStatus = True
		Local n:Int ; For n=0 Until This._buffercount ; This.FillBuffer(n) ; Next
		alSourceQueueBuffers(This._source, This._buffercount, This._buffers);
		alSourcePlay This._source
		Return This
	EndFunction

	Method New()
		alGenBuffers(_buffercount,_buffers)
		Local n:Int ; For n=0 Until _bufferbanks.length
			_bufferbanks[n] = CreateBank(_buffersize)
		Next
		alGenSources(1, Varptr _source);
    	alSource3f(_source, AL_POSITION,        0.0, 0.0, 0.0)
    	alSource3f(_source, AL_VELOCITY,        0.0, 0.0, 0.0)
    	alSource3f(_source, AL_DIRECTION,       0.0, 0.0, 0.0)
    	alSourcef (_source, AL_ROLLOFF_FACTOR,  0.0          )
    	alSourcei (_source, AL_SOURCE_RELATIVE, AL_TRUE      )

'		Print "created openal stream"
	EndMethod

	Method Update()
		If Music.Geti(MM_ISPLAYING)=False And Not Playing() Stop ; Return
		Local buffer:Int, n:Int, n1:Int, processed:Int
		alGetSourcei(_source, AL_BUFFERS_PROCESSED, Varptr processed);
		For n=0 Until processed
			alSourceUnqueueBuffers(_source, 1, Varptr buffer); 
			If Music.Geti(MM_ISPLAYING)
				For n1=0 Until _buffercount
					If _buffers[n1]=buffer FillBuffer(n1) ; Exit
				Next
				alSourceQueueBuffers(_source, 1, Varptr buffer);      
			EndIf
		Next
		If Not Playing() And Not paused alSourcePlay _source
	EndMethod
	
	Method FillBuffer(bufferindex:Int)
		Local data:Byte Ptr = BankBuf(_bufferbanks[bufferindex])
		Music.FillBuffer( Int(data), _buffersize)
		alBufferData(_buffers[bufferindex], AL_FORMAT_STEREO16, data, _buffersize, samplerate);
	EndMethod

	Method Stop()
		If Not _source Return
		alSourceStop(_source)
		RemoveHook EmitEventHook,eventhook,Self
		alDeleteSources(1,Varptr _source)	; _source = Null
		alDeleteBuffers(_buffercount,_buffers)
		If Not KeepMusic Then Music.Free
		Music 			= Null
		_buffers 		= Null
		_bufferbanks 	= Null
		_source 		= Null
		GCCollect
	EndMethod

	Method SetPaused( paused:Int )
		If Not _source Return
		If paused And Self.Paused=False
			Self.Paused = paused
			alSourceStop(_source)
		ElseIf paused=False And Self.paused
			Self.Paused = paused
			Music.PlayStatus = True
			alSourcePlay _source
		EndIf
	End Method

	Method SetVolume( volume# )
		If Not _source Return
		alSourcef _source,AL_GAIN,volume
	End Method

	Method SetPan( pan# ) 
		If Not _source Return
		pan=Min(Max(pan,-1),1)*90
		alSource3f(_source,AL_POSITION,Sin(pan),0,-Cos(pan))
	End Method

	Method SetDepth( depth# )
	End Method

	Method SetRate( rate# )
		If Not _source Return
		alSourcef _source,AL_PITCH,rate
	End Method
	
	Method Playing:Int()
		If Not _source Return 0
		Local status:Int
		alGetSourcei(_source,AL_SOURCE_STATE,Varptr status)
		If status = AL_PLAYING Return True
	End Method

EndType